﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.Serialization;
using System.ServiceModel;
using RG.Common;
using RG.Common.Const;
using Microsoft.Practices.Unity;

namespace RG.Common
{
    /// <summary>
    /// Интерфейс для доступа из презентеров к визуальной части приложения
    /// 
    /// На самом деле получается 2 варианта
    /// 1. Заложиться на то, что для каждого презентера будет только одно представление (не нравится)
    /// 2. Каким-то образом указывать какое представление показывать в данный момент
    /// 
    /// Доставаться все должно из контейнера. Вариант с именованием View не нравится, т.к. строки. 
    /// Но с другой стороны как сказать какой View показывать если их надо несколько на один презентер ?
    /// 
    /// Хотя конечно можно сделать хитро, например если презентер сделать 
    /// class Presenter: IPresenterForView1, IPresenterForView2
    /// В интерфейсы можно выносить например методы для обработки событий (всякие Click).
    /// </summary>
    
    public interface IWorkplace
    {
        /// <summary>
        /// Контейнер для этого Workplace
        /// </summary>
        IUnityContainer Cfg { get; }

        /// <summary>
        /// Показывает где-то там у себя окно или фрейм (зависит от реализации) с переданным презентером
        /// </summary>
        /// <param name="presenter">Экземпляр презентера окна</param>
        void Show<TPresenter>(TPresenter presenter);

        /// <summary>
        /// Закрывает экземпляр окна для переданного презентера. Как IWorkplace будет искать окно для переданного презентера - зависит от реализации
        /// </summary>
        /// <param name="presenter">Экземпляр презентера окна</param>
        void Close(object presenter);

        /// <summary>
        /// Показывает модальный диалог. При этом IView должен быть обязательно UserControl
        /// </summary>
        /// <param name="presenter">Презентер который используется для формы</param>
        /// <param name="caption">Заголовок окна</param>
        bool ShowDialog<TPresenter>(TPresenter presenter, string caption);

        /// <summary>
        /// Показывает EditableObjectDlg для presenter. Можно было обойтись и Extension-ом, но тогда фигово тесты писать
        /// </summary>
        /// <typeparam name="TEditableObject"></typeparam>
        /// <param name="presenter">Редактируемый объект</param>
        /// <param name="caption">Заголовок окна</param>
        /// <returns></returns>
        bool ShowEditableDialog<TEditableObject>(TEditableObject presenter, string caption) where TEditableObject : IEditableObject;

        /// <summary>
        /// Показывает EditableObjectDlg для presenter. Можно было обойтись и Extension-ом, но тогда фигово тесты писать
        /// </summary>
        /// <typeparam name="TEditableObject"></typeparam>
        /// <param name="presenter">Редактируемый объект</param>
        /// <param name="caption">Заголовок окна</param>
        /// <returns></returns>
        bool ShowEditableDialog<TEditableObject>(TEditableObject presenter, string caption,string okText,string cancelText) where TEditableObject : IEditableObject;

        /// <summary>
        /// показываем окно напоминалок
        /// </summary>
        /// <typeparam name="TalarmManager"></typeparam>
        /// <param name="frame"></param>
        /// <param name="id"></param>
        void ShowAlarm<TalarmManager>(TalarmManager frame, int id);

        /// <summary>
        /// просто для закрытия окна напоминалок из дочернего окна
        /// </summary>
        void CloseAlarm();

        /// <summary>
        /// Закрывает текущий модальный диалог
        /// </summary>
        /// <param name="isOk"></param>
        void CloseDialog(bool isOk);

        /// <summary>
        /// Завершает текущий Workplace
        /// </summary>
        void Shutdown();

        /// <summary>
        /// Показывает ругательное сообщение
        /// </summary>
        /// <param name="errorText">Ругательное сообщение</param>
        void Error(string errorText);

        /// <summary>
        /// Показывает информационное сообщение
        /// </summary>
        /// <param name="infoText">Информационное сообщение</param>
        void Information(string infoText);

        /// <summary>
        /// Спрашивает у пользователеля чего-то там модально
        /// </summary>
        /// <param name="askText">Вопрос сообщение</param>
        /// <rereturns>Да - true, Нет - false, Отмена - null</rereturns>
        bool? Ask(string askText);

        /// <summary>
        /// Спрашивает у пользователеля чего-то там модально с выбором да или нет
        /// </summary>
        /// <param name="askText">Вопрос сообщение</param>
        /// <rereturns>Да - true, Нет - false</rereturns>
        bool AskYesNo(string askText);

        void PrintReport<TFactory, T>(T initVal, ReportPaperSize reportPaperSize = ReportPaperSize.A4Portrait)
            where TFactory : IReportfactoryBase<T>;

        string SaveReport<TFactory, T>(T initVal, ReportPaperSize reportPaperSize = ReportPaperSize.A4Portrait)
            where TFactory : IReportfactoryBase<T>;

        void PrintReportFromFile(string path,string name);

        string SelfScreen();

        event EventHandler ReportPrintPressed;
        
    }

    public interface IView<T> 
    {
        T Presenter { get; set; }
    }

    public interface IWorkplaceObject
    {
        bool CanClose { get; }
    }

    public interface IOnShow
    {
        void OnShow();
    }

    public interface IChildView
    {
        object ChildView { get;  }

        object Child { get; }
        
        void SetChild<TPresenter>(TPresenter child);
    }

    public class ViewStub<T>: IView<T>
    {
        public T Presenter { get; set; }
    }
    
    public interface IReportfactoryBase<T>
    {
        void InitTemplateConstructor();

        List<object> InitPages(T initValue);

        string Name { get; set; }
    }

    public interface IReportPrintHistory
    {
        void PutHistory();
    }

    public interface IValidateBeforePrint
    {
        bool DoValidate();
    }

    public interface IAlarmObj
    {
        DateTime AlarmTime { get; set; }

        int ObjId { get; set; }
    }

    public interface IAlarmFrame
    {
        /// <summary>
        /// Это метод инициализации окна сообщений
        /// в нем желательно сходить в базу и пошукать все что надо показать с отработкой логики 
        /// того что является просроченым а что нет
        /// </summary>
        /// <param name="managerId"></param>
        void Init(int managerId);

        /// <summary>
        /// А это на случай если окошко напоминалок активно
        /// но диспечер напоминалок пинает о том что есть новые сообщения
        /// </summary>
        /// <param name="managerId"></param>
        void Refresh(int managerId);

        /// <summary>
        /// флаг чтобы не звать повторно обновление списка ежели оно уже
        /// в процессе
        /// </summary>
        bool IsFree { get; }

        /// <summary>
        /// Событие которое поддтверждает что есть активные сообщения 
        /// которые надо показать
        /// </summary>
        event AlarmShowEventArgs CanShowAlarm;
    }

    public delegate void AlarmShowEventArgs();

    [ServiceContract(SessionMode = SessionMode.NotAllowed)]
    public interface IAlarmService
    {
        [OperationContract]
        AlarmObject GetFirstAlarmTime(int managerId);
        [OperationContract]
        List<int> GetActivAlarmList(int managerId);
        [OperationContract]
        void MarkAlarmCompleate(int id);
        [OperationContract]
        void MoveAlarmTime(int id, DateTime newTime);
    }

    [DataContract]
    [SupportDataBinding]
    public class AlarmObject : IAlarmObj
    {
        [DataMember]
        public DateTime AlarmTime { get; set; }

        [DataMember]
        public int ObjId { get; set; }

        [DataMember]
        public bool NotExpired { get; set; }
    }

    public abstract class ReportfactoryBase<T> : IReportfactoryBase<T>
    {
        public virtual void InitTemplateConstructor() { }

        public abstract List<object> InitPages(T initValue);

        public string Name { get; set; }
    }

    public static class UnityContainerCreateViewExtension
    {
        public static object CreateView(this IUnityContainer container, object presenterVM)
        {
            #region container.Resolve<IView<presenterVM>>

            var viewGenericType = typeof (IView<>);
            var viewType = viewGenericType.MakeGenericType(new[] {presenterVM.GetType()});
            var obj = container.Resolve(viewType);
            
            #endregion

            #region obj.Presenter = presenterVM 
            
            var methodInfo = viewType.GetMethod("set_Presenter");
            methodInfo.Invoke(obj, new[] { presenterVM });
            
            #endregion
            
            return obj;
        }
    }
}